<!DOCTYPE html>
<html lang="zh-cn">
  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="author" content="Zhou Wei <zromyk@163.com>">
  <title>Redis 数据库</title>
  <link rel="shortcut icon" href="/favicon.ico">
  <link rel="stylesheet" href="/style/html/pure.css">
  <link rel="stylesheet" href="/style/html/main.css">
  <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css">
  <!-- <link rel="stylesheet" href="https://apps.bdimg.com/libs/highlight.js/9.1.0/styles/default.min.css"> -->
<link rel="stylesheet" href="/style/article/highlight/default.min.css">
<link rel="stylesheet" href="/style/article/pell-1.0.6/dist/pell.css">

</head>
<body>
  <div id="menu-background"></div>
  <div id="menu">
    <div class="pure-menu pure-menu-horizontal">
  <ul class="pure-menu-list block-middle">
    <li class="pure-menu-item">
  <a class="pure-menu-heading" href="/index.html">ZROMYK</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/index.html">主页</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/archive/index.html">归档</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/download/index.html">下载</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/feedback/index.html">反馈</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/about/index.html">关于我</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="https://github.com/zromyk"><i class="fa fa-github" style="font-size:32px"></i></a>
</li>

  </ul>
</div>

  </div>
  <div id="layout">
    <div class="content">
      <div id="nav">
    <div id="navigation" class="navigation">
  <ul class="pure-menu-list">
    <li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis">一、Redis 简介</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis_1">二、Redis 优势</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis-key-value">三、Redis 与其他 key-value 存储有什么不同？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#linux-redis">四、Linux 安装 Redis</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#1">1. 下载</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#2">2. 解压</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#3">3. 安装</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#4">4. 移动配置文件到安装目录下</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#5-redis">5. 配置 redis 为后台启动</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#6-redis">6. 将 redis 加入到开机启动</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#7-redis">7. 开启 redis</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#8-redis-cli-redis-server-bin">8. 将 redis-cli, redis-server 拷贝到 bin 下</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#9-redis">9. 设置redis密码</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#_1">命令</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#1-redis">1. 启动 redis</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#2-redis">2. 停止 redis</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#3-redis">3. 卸载 redis</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#4_1">4. 检测后台进程是否存在</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#5-6379">5. 检测 6379 端口是否在监听</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis_2">五、Redis 数据类型</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#string">String（字符串）</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#hash">Hash（哈希）</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#list">List（列表）</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#set">Set（集合）</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#zsetsorted-set">zset(sorted set：有序集合)</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis_3">六、Redis 命令</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#1-redis_1">1. 启动 Redis 客户端</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#_2">在远程服务上执行命令</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis-key">七、Redis 键(key)</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis-hyperloglog">八、Redis HyperLogLog</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav4" onclick="animateByNav()" href="#_3">什么是基数?</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis_4">九、Redis 发布订阅</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis_5">十、Redis 事务</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#redis_6">十一、Redis 脚本</a>
</li>

  </ul>
</div>

</div>
<div id="content-articles">
  <h1 id="Redis 数据库" class="content-subhead">Redis 数据库</h1>
  <p>
    <span>2021-04-17</span>
    <span><span class="post-category post-category-other">数据库</span></span>
    <button id="button-markdownEditor" class="pure-button" onclick="markdownEditor()">启用编辑</button>
    <button id="button-save" class="pure-button" onclick="save()">保存</button>
  </p>
  <div id="content-articles-markdownEditor" style="display: none;">
    <h1>编辑 power by pell</h1>
    <div id="editor" class="pell"></div>
    <div style="margin-top:20px;">
        <h3>Text output:</h3>
        <div id="text-output"></div>
    </div>
    <div style="margin-top:20px;">
        <h3>HTML output:</h3>
        <pre id="html-output"></pre>
    </div>
  </div>
  <div id="content-articles-markdown">
    <h2 id="redis">一、Redis 简介</h2>
<p>Redis 是完全开源的，遵守 BSD 协议，是一个高性能的 key-value 数据库。</p>
<p>Redis 与其他 key - value 缓存产品有以下三个特点：</p>
<ul>
<li>Redis 支持数据的持久化，可以将内存中的数据保存在磁盘中，重启的时候可以再次加载进行使用。</li>
<li>Redis 不仅仅支持简单的 key-value 类型的数据，同时还提供list，set，zset，hash等数据结构的存储。</li>
<li>Redis 支持数据的备份，即 master-slave 模式的数据备份。</li>
</ul>
<h2 id="redis_1">二、Redis 优势</h2>
<ul>
<li><strong>性能极高</strong> – Redis能读的速度是110000次/s,写的速度是81000次/s 。</li>
<li><strong>丰富的数据类型</strong> – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。</li>
<li><strong>原子</strong> – Redis的所有操作都是原子性的，意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务，即原子性，通过MULTI和EXEC指令包起来。</li>
<li><strong>丰富的特性</strong> – Redis还支持 publish/subscribe, 通知, key 过期等等特性。</li>
</ul>
<h2 id="redis-key-value">三、Redis 与其他 key-value 存储有什么不同？</h2>
<ul>
<li><strong>Redis 有着更为复杂的数据结构并且提供对他们的原子性操作</strong>，这是一个不同于其他数据库的进化路径。<strong>Redis的数据类型都是基于基本数据结构的同时对程序员透明</strong>，无需进行额外的抽象。</li>
<li><strong>Redis 运行在内存中但是可以持久化到磁盘</strong>，所以在对不同数据集进行高速读写时需要权衡内存，因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是，相比在磁盘上相同的复杂的数据结构，在内存中操作起来非常简单，<strong>这样 Redis 可以做很多内部复杂性很强的事情</strong>。同时，在磁盘格式方面他们是紧凑的以追加的方式产生的，因为他们并不需要进行随机访问。</li>
</ul>
<p>注意：</p>
<ul>
<li>Redis 支持多个数据库，并且每个数据库的数据是隔离的不能共享，并且基于单机才有，如果是集群就没有数据库的概念。</li>
<li>Redis 是一个 <strong>字典结构</strong> 的存储服务器，而实际上一个 Redis 实例提供了多个用来存储数据的字典，客户端可以指定将数据存储在哪个字典中。这与我们熟知的在一个关系数据库实例中可以创建多个数据库类似，所以可以将其中的每个字典都理解成一个独立的数据库。</li>
<li>每个数据库对外都是一个从 0 开始的递增数字命名，Redis 默认支持 16 个数据库（可以通过配置文件支持更多，无上限），可以通过配置 databases 来修改这一数字。客户端与 Redis 建立连接后会自动选择 0 号数据库，不过可以随时使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>SELECT</code></span> 命令更换数据库，如要选择1号数据库：<span style="overflow-x: auto; max-width:100%; display:inline;"><code>redis&gt; SELECT 1</code></span><ul>
<li>然而这些以数字命名的数据库又与我们理解的数据库有所区别。</li>
<li>首先，Redis <strong>不支持自定义数据库的名字</strong>，每个数据库都以编号命名，开发者必须自己记录哪些数据库存储了哪些数据。</li>
<li>另外，Redis <strong>不支持为每个数据库设置不同的访问密码</strong>，所以一个客户端要么可以访问全部数据库，要么连一个数据库也没有权限访问。</li>
<li>最重要的一点，<strong>多个数据库之间并不是完全隔离的</strong>，比如 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>FLUSHALL</code></span> 命令可以清空一个 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>Redis</code></span> 实例中所有数据库中的数据。</li>
<li>综上所述，这些数据库更像是一种命名空间，而不适宜存储不同应用程序的数据。比如可以使用 0 号数据库存储某个应用生产环境中的数据，使用 1 号数据库存储测试环境中的数据，但不适宜使用 0 号数据库存储 A 应用的数据而使用 1 号数据库 B 应用的数据，<strong>不同的应用应该使用不同的 Redis 实例存储数据。</strong></li>
</ul>
</li>
<li>由于 Redis 非常轻量级，一个空 Redis 实例占用的内在只有 1M 左右，所以不用担心多个 Redis 实例会额外占用很多内存。</li>
</ul>
<h2 id="linux-redis">四、Linux 安装 Redis</h2>
<blockquote class="content-quote">
<p>https://www.cnblogs.com/happywish/p/10944253.html</p>
</blockquote>
<h4 id="1">1. 下载</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">wget http://download.redis.io/releases/redis-4.0.8.tar.gz
</code></span></code></pre>
<h4 id="2">2. 解压</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">tar xzvf redis-4.0.8.tar.gz
</code></span></code></pre>
<h4 id="3">3. 安装</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">cd redis-4.0.8
make
cd src
make install PREFIX=/usr/local/redis
</code></span></code></pre>
<h4 id="4">4. 移动配置文件到安装目录下</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">cd ../
mkdir /usr/local/redis/etc
mv redis.conf /usr/local/redis/etc
</code></span></code></pre>
<h4 id="5-redis">5. 配置 redis 为后台启动</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">vi /usr/local/redis/etc/redis.conf
# 将 daemonize no 改成 daemonize yes
</code></span></code></pre>
<h4 id="6-redis">6. 将 redis 加入到开机启动</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">vi /etc/rc.local
# 在里面添加内容：/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
</code></span></code></pre>
<h4 id="7-redis">7. 开启 redis</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
</code></span></code></pre>
<h4 id="8-redis-cli-redis-server-bin">8. 将 redis-cli, redis-server 拷贝到 bin 下</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">cp /usr/local/redis/bin/redis-server /usr/local/bin/
cp /usr/local/redis/bin/redis-cli /usr/local/bin/
</code></span></code></pre>
<h4 id="9-redis">9. 设置redis密码</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell"># 运行 Redis
redis-cli
# 查看现有的 redis 密码
127.0.0.1:6379&gt; config get requirepass
1) &quot;requirepass&quot;
2) &quot;&quot;
# 设置 redis 密码，设置成功的话会返回‘OK’字样
127.0.0.1:6379&gt; config set requirepass ****
</code></span></code></pre>
<h3 id="_1">命令</h3>
<h4 id="1-redis">1. 启动 redis</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">redis-server /usr/local/redis/etc/redis.conf # 以指定配置文件启动
redis-server &amp; # 加上`&amp;`号使redis以后台程序方式运行，可以直接 redis-server 启动
</code></span></code></pre>
<h4 id="2-redis">2. 停止 redis</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">pkill redis
</code></span></code></pre>
<h4 id="3-redis">3. 卸载 redis</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">rm -rf /usr/local/redis             # 删除安装目录
rm -rf /usr/bin/redis-*             # 删除所有redis相关命令脚本
rm -rf /root/download/redis-4.0.4   # 删除redis解压文件夹
</code></span></code></pre>
<h4 id="4_1">4. 检测后台进程是否存在</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">ps -ef |grep redis
# ps -ef 表示查看全格式的全部进程。
#       -e 显示所有进程。
#       -f 全格式。
</code></span></code></pre>
<h4 id="5-6379">5. 检测 6379 端口是否在监听</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">netstat -lntp | grep 6379
</code></span></code></pre>
<h2 id="redis_2">五、Redis 数据类型</h2>
<p>Redis支持五种数据类型：</p>
<ul>
<li>string（字符串）</li>
<li>hash（哈希）</li>
<li>list（列表）</li>
<li>set（集合）</li>
<li>zset (sorted set：有序集合)</li>
</ul>
<p>各个数据类型应用场景：</p>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th align="left">类型</th>
<th align="left">简介</th>
<th align="left">特性</th>
<th align="left">场景</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">String (字符串)</td>
<td align="left">二进制安全</td>
<td align="left">可以包含任何数据，比如 jpg 图片或者序列化的对象,一个键最大能存储 512 M</td>
<td align="left">&mdash;</td>
</tr>
<tr>
<td align="left">Hash (字典)</td>
<td align="left">键值对集合，即编程语言中的 Map 类型</td>
<td align="left">适合存储对象，并且可以像数据库中 update 一个属性一样只修改某一项属性值<br /> (Memcached 中需要取出整个字符串反序列化成对象修改完再序列化存回去)</td>
<td align="left">存储、读取、修改用户属性</td>
</tr>
<tr>
<td align="left">List (列表)</td>
<td align="left">链表(双向链表)</td>
<td align="left">增删快，提供了操作某一段元素的API</td>
<td align="left">1、最新消息排行等功能 (比如朋友圈的时间线) <br />2、消息队列</td>
</tr>
<tr>
<td align="left">Set (集合)</td>
<td align="left">哈希表实现，元素不重复</td>
<td align="left">1、添加、删除,查找的复杂度都是O(1) <br />2、为集合提供了求交集、并集、差集等操作</td>
<td align="left">1、共同好友 <br />2、利用唯一性,统计访问网站的所有独立 ip <br />3、好友推荐时,根据 tag 求交集,大于某个阈值就可以推荐</td>
</tr>
<tr>
<td align="left">Sorted Set (有序集合)</td>
<td align="left">将 Set 中的元素增加一个权重参数 score，元素按score 有序排列</td>
<td align="left">数据插入集合时，已经进行天然排序</td>
<td align="left">1、排行榜 <br />2、带权重的消息队列</td>
</tr>
</tbody>
</table></div>
<h3 id="string">String（字符串）</h3>
<p><a href="https://www.runoob.com/redis/redis-strings.html">https://www.runoob.com/redis/redis-strings.html</a></p>
<ul>
<li>string 是 redis 最基本的类型，你可以理解成与 Memcached 一模一样的类型，一个 key 对应一个 value。</li>
<li>string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。</li>
<li>string 类型是 Redis 最基本的数据类型，string 类型的值最大能存储 512MB。</li>
<li><strong>注意：</strong>一个键最大能存储 512MB。</li>
</ul>
<h3 id="hash">Hash（哈希）</h3>
<p><a href="https://www.runoob.com/redis/redis-hashes.html">https://www.runoob.com/redis/redis-hashes.html</a></p>
<ul>
<li>Redis hash 是一个键值(key=&gt;value)对集合。</li>
<li>Redis hash 是一个 string 类型的 field 和 value 的映射表，hash 特别适合用于存储对象。</li>
<li>每个 hash 可以存储 232 -1 键值对（40多亿）。</li>
</ul>
<h3 id="list">List（列表）</h3>
<p><a href="https://www.runoob.com/redis/redis-lists.html">https://www.runoob.com/redis/redis-lists.html</a></p>
<ul>
<li>Redis 列表是简单的字符串列表，按照插入顺序排序。你可以添加一个元素到列表的头部（左边）或者尾部（右边）。</li>
<li>列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。</li>
</ul>
<h3 id="set">Set（集合）</h3>
<p><a href="https://www.runoob.com/redis/redis-sets.html">https://www.runoob.com/redis/redis-sets.html</a></p>
<ul>
<li>Redis 的 Set 是 string 类型的无序集合。</li>
<li>集合是通过哈希表实现的，所以添加，删除，查找的复杂度都是 O(1)。</li>
<li>集合中最大的成员数为 232 - 1(4294967295, 每个集合可存储40多亿个成员)。</li>
</ul>
<h3 id="zsetsorted-set">zset(sorted set：有序集合)</h3>
<p><a href="https://www.runoob.com/redis/redis-sorted-sets.html">https://www.runoob.com/redis/redis-sorted-sets.html</a></p>
<ul>
<li>Redis zset 和 set 一样也是 string 类型元素的集合，且不允许重复的成员。</li>
<li>不同的是 <strong>每个元素都会关联一个 double 类型的分数</strong>。redis 正是通过分数来为集合中的成员进行从小到大的排序。</li>
<li>zset 的成员是唯一的，但分数 (score) 却可以重复。</li>
</ul>
<h2 id="redis_3">六、Redis 命令</h2>
<h3 id="1-redis_1">1. 启动 Redis 客户端</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">$ redis-cli

# 实例
$ redis-cli
127.0.0.1:6379&gt; PING
PONG
# 在以上实例中我们连接到本地的 redis 服务并执行 PING 命令
# PING 命令用于检测 redis 服务是否启动。

# 有时候会有中文乱码，解决方法：
$ redis-cli -raw
</code></span></code></pre>
<h4 id="_2">在远程服务上执行命令</h4>
<p>如果需要在远程 redis 服务上执行命令，同样我们使用的也是 <strong>redis-cli</strong> 命令。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">$ redis-cli -h host -p port -a password

# 实例
$redis-cli -h 127.0.0.1 -p 6379 -a &quot;mypass&quot;
127.0.0.1:6379&gt; PING
PONG
</code></span></code></pre>
<h2 id="redis-key">七、Redis 键(key)</h2>
<p><a href="https://www.runoob.com/redis/redis-keys.html">https://www.runoob.com/redis/redis-keys.html</a></p>
<h2 id="redis-hyperloglog">八、Redis HyperLogLog</h2>
<p>Redis 在 2.8.9 版本添加了 HyperLogLog 结构。</p>
<p>Redis HyperLogLog 是用来做 <strong>基数统计</strong> 的算法，HyperLogLog 的优点是，在输入元素的数量或者体积非常非常大时，计算基数所需的空间总是固定的、并且是很小的。</p>
<p>在 Redis 里面，每个 HyperLogLog 键只需要花费 12 KB 内存，就可以计算接近 2^64 个不同元素的基数。这和计算基数时，元素越多耗费内存就越多的集合形成鲜明对比。</p>
<p>但是，因为 HyperLogLog 只会根据输入元素来计算基数，而不会储存输入元素本身，所以 HyperLogLog 不能像集合那样，返回输入的各个元素。</p>
<h4 id="_3">什么是基数?</h4>
<p>比如数据集 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>{1, 3, 5, 7, 5, 7, 8}</code></span>， 那么这个数据集的基数集为 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>{1, 3, 5 ,7, 8}</code></span>，基数的个数（不重复元素）为 5。</p>
<h2 id="redis_4">九、Redis 发布订阅</h2>
<p>Redis 发布订阅 (pub/sub) 是一种消息通信模式：发送者 (pub) 发送消息，订阅者 (sub) 接收消息。</p>
<p>Redis 客户端可以订阅任意数量的频道。</p>
<p>下图展示了频道 channel1 ， 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系：</p>
<p><img class="pure-img" alt="img" src="https://zromyk.gitee.io/myblog-figurebed/post/Redis-数据库.assets/pubsub1.png" /></p>
<p>当有新消息通过 PUBLISH 命令发送给频道 channel1 时， 这个消息就会被发送给订阅它的三个客户端：</p>
<p><img class="pure-img" alt="img" src="https://zromyk.gitee.io/myblog-figurebed/post/Redis-数据库.assets/pubsub2.png" /></p>
<h2 id="redis_5">十、Redis 事务</h2>
<p><strong>Redis 事务可以一次执行多个命令</strong>， 并且带有以下三个重要的保证：</p>
<ul>
<li>批量操作在发送 EXEC 命令前被放入队列缓存。</li>
<li>收到 EXEC 命令后进入事务执行，事务中任意命令执行失败，其余的命令依然被执行。</li>
<li>在事务执行过程，其他客户端提交的命令请求不会插入到事务执行命令序列中。</li>
</ul>
<p>一个事务从开始到执行会经历以下三个阶段：</p>
<ul>
<li>开始事务。</li>
<li>命令入队。</li>
<li>执行事务。</li>
</ul>
<h2 id="redis_6">十一、Redis 脚本</h2>
<p>Redis 脚本使用 Lua 解释器来执行脚本。 Redis 2.6 版本通过内嵌支持 Lua 环境。执行脚本的常用命令为 <strong>EVAL</strong>。</p>
  </div>
</div>
 
    </div>
  </div>
  <div id="footer-background">
    <div id="footer">
      <div class="legal pure-g">
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-license"><a href="https://beian.miit.gov.cn/#/Integrated/index">浙ICP备2020038748号</a></p>
  </div>
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-links"><a href="https://github.com/zromyk">GitHub</a></p>
    <p class="legal-copyright">Copyright © 2021 Wei Zhou. 保留所有权利。</p>
  </div>
</div>
    </div>
  </div>
  <!-- <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> -->
  <script src="/style/html/jquery.min.js"></script>
  <script src='/style/article/latex/latest.js?config=TeX-MML-AM_CHTML'></script>
<!-- <script src="https://cdn.geogebra.org/apps/deployggb.js"></script> -->
<script src="/style/article/deployggb.js"></script>
<!-- <script src="https://apps.bdimg.com/libs/highlight.js/9.1.0/highlight.min.js"></script> -->
<script type="text/javascript">
  // 脚本：navigation 随鼠标移动自动变换宽度
  var element = document.getElementById("navigation"); // 获取要操作的元素
  var elementWidth = parseInt(getComputedStyle(element).width);
  var elementLeft = 0;
  var elementRight = 0;
  element.addEventListener('mouseenter', function (event) { // 添加鼠标按下事件的监听器
    elementLeft = element.getBoundingClientRect().left - 10;
    elementRight = element.getBoundingClientRect().left + elementWidth * 3;
    window.addEventListener('mousemove', resize); // 添加全局的鼠标移动事件的监听器
  });

  function resize(event) {
    var minWidth = elementWidth;
    var maxWidth = elementWidth * 2.5;
    // console.log(elementLeft, event.clientX, elementRight, event.clientX - elementLeft + elementWidth / 2);
    if (elementLeft <= event.clientX && event.clientX <= elementRight) {
      var width = event.clientX - elementLeft + elementWidth / 2;
      width = Math.min(width, maxWidth);
      width = Math.max(width, minWidth);
      element.style.width = width + 'px'; // 设置新的宽度样式属性
    }
    else {
      element.style.width = elementWidth + 'px'; // 设置新的宽度样式属性
      stopResize();
    }
  }

  function stopResize() {
    element.style.width = elementWidth + 'px'; // 设置新的宽度样式属性
    // console.log("stopResize", elementLeft, event.clientX, elementRight, event.clientX - elementLeft + elementWidth / 2);
    window.removeEventListener('mousemove', resize); // 移除鼠标移动事件的监听器
  }
</script>
<script src="/style/article/highlight/highlight.min.js"></script>
<script type="text/javascript">
  // 脚本：code语法高亮
  hljs.initHighlightingOnLoad();
</script>
<script>
  function animateByNav() {
    $("html").animate({
        scrollTop: ($(event.target.hash).offset().top - 52)
    }, 300);
  };
</script>
<script src="/style/article/pell-1.0.6/dist/pell.js"></script>
<script>
  // 脚本：自由编辑页面
  var editor = window.pell.init({
    element: document.getElementById('editor'),
    defaultParagraphSeparator: 'p',
    onChange: function(html) {
        document.getElementById('text-output').innerHTML = html
        document.getElementById('html-output').textContent = html
    }
  });

  function markdownEditor() {
    var articles = document.getElementById('content-articles-markdown');
    if (articles.getAttribute("contenteditable") == "true") {
        articles.setAttribute("contenteditable", "false");
        document.getElementById("content-articles-markdownEditor").style.display = "none"; //隐藏
        document.getElementById("button-markdownEditor").innerHTML = "启用编辑";
    } else {
        articles.setAttribute("contenteditable", "true");
        document.getElementById("content-articles-markdownEditor").style.display = ""; //显示
        document.getElementById("button-markdownEditor").innerHTML = "关闭编辑";
    }
  };

  function save() {
      window.alert("保存成功");
  };
</script>

</body>
</html>
